package com.magnificent.atlantis.client.robot.strategies;

import com.magnificent.atlantis.client.data.configuration.ServerConfiguration;
import com.magnificent.atlantis.client.data.task.common.TaskImportance;
import com.magnificent.atlantis.client.data.task.planner.BasicPlannerTask;
import com.magnificent.atlantis.client.data.task.planner.CommunityMeetingPlannerTask;
import com.magnificent.atlantis.client.event.EventDispatcher;
import com.magnificent.atlantis.client.event.EventType;
import com.magnificent.atlantis.client.robot.RobotContext;
import com.magnificent.atlantis.client.scheduler.SchedulerCallBack;
import com.magnificent.atlantis.common.entity.ServerUser;
import com.magnificent.commons.utils.DateUtils;
import com.magnificent.commons.utils.TimeConstants;
import com.magnificent.commons.utils.collections.list.MetaArrayList;
import com.magnificent.commons.utils.collections.list.MetaList;
import com.magnificent.commons.utils.collections.list.functions.SelectFunction;

import java.util.Date;
import java.util.Random;

/**
 * User: Babanin
 * Date: 13.08.2009
 * Time: 1:05:09
 */
public abstract class RobotStrategy implements Runnable, SchedulerCallBack {

    public static final int WORK_DATE_START = 8;
    public static final int WORK_DATE_END = 18;

    private Random random;
    private RobotContext robotContext;

    protected RobotStrategy(RobotContext robotContext) {
        this.robotContext = robotContext;

        random = new Random();
    }

    protected void generateSimpleTasks(int count) {
        ServerConfiguration serverConfiguration =
                (ServerConfiguration) robotContext.getPlannerData().getConfigurationContainer().getConfigurations().get(0);

        while (count-- != 0) {
            BasicPlannerTask task = new BasicPlannerTask();

            long day = DateUtils.startOfDayInMillis(new Date().getTime()) +
                    TimeConstants.MLS_IN_DAY +
                    getRandom(0, robotContext.getDayPeriod()) * TimeConstants.MLS_IN_DAY;

            Date startDate =
                    new Date(
                            day +
                                    robotContext.getWorkDayStart() * TimeConstants.MLS_IN_HOUR +
                                    getRandom(0, 9) * TimeConstants.MLS_IN_HOUR
                    );

            long endOfDay = day + robotContext.getWorkDayFinish() * TimeConstants.MLS_IN_HOUR;

            if (endOfDay < startDate.getTime()) {
                System.out.println("");
            }

            long randomDuration = getRandom((int) (30 * TimeConstants.MLS_IN_MIN), (int) (endOfDay - startDate.getTime()));

            task.setStartDate(startDate);
            task.setDuration(randomDuration);
            task.setTaskImportance(TaskImportance.values()[getRandom(0, TaskImportance.values().length)]);

            task.setConfigurationId(serverConfiguration.getId());

            robotContext.getPlannerData().getConfigurationContainer().getDataTasks().add(task);
            EventDispatcher.getInstance(robotContext).postEvent(EventType.NEW_TASK, task);
        }
    }

    protected void generateMeetingTasks(int count) {
        ServerConfiguration serverConfiguration =
                (ServerConfiguration) robotContext.getPlannerData().getConfigurationContainer().getConfigurations().get(0);

        while (count-- != 0) {
            CommunityMeetingPlannerTask task = new CommunityMeetingPlannerTask();

            long day = DateUtils.startOfDayInMillis(new Date().getTime()) +
                    TimeConstants.MLS_IN_DAY +
                    getRandom(0, robotContext.getDayPeriod()) * TimeConstants.MLS_IN_DAY;

            Date startDate =
                    new Date(
                            day +
                                    robotContext.getWorkDayStart() * TimeConstants.MLS_IN_HOUR +
                                    getRandom(0, 9) * TimeConstants.MLS_IN_HOUR
                    );

            long endOfDay = day + robotContext.getWorkDayFinish() * TimeConstants.MLS_IN_HOUR;

            if (endOfDay < startDate.getTime()) {
                System.out.println("");
            }

            long randomDuration = getRandom((int) (30 * TimeConstants.MLS_IN_MIN), (int) (endOfDay - startDate.getTime()));

            task.setStartDate(startDate);
            task.setDuration(randomDuration);
            task.setEndDate(new Date(startDate.getTime() + randomDuration));
            task.setTaskImportance(TaskImportance.values()[getRandom(0, TaskImportance.values().length)]);

            task.setConfigurationId(serverConfiguration.getId());
            task.setInvitedUsers(getRandomUsers(1).toList());

            robotContext.getPlannerData().getConfigurationContainer().getDataTasks().add(task);
            EventDispatcher.getInstance(robotContext).postEvent(EventType.NEW_TASK, task);
        }
    }

    protected int getRandom(int min, int max) {
        if (min >= max) {
            return 0;
        }

        int randomInt = random.nextInt(max);

        while (randomInt < min) {
            randomInt = random.nextInt(max);
        }

        return randomInt;
    }

    protected MetaList<Integer> getRandomUsers(int max) {
        int userCount = robotContext.getUsers().size();

        if (userCount == 0) {
            return new MetaArrayList<Integer>();
        } else {
            if (userCount <= max) {
                return new MetaArrayList<ServerUser>(robotContext.getUsers()).select(new SelectFunction<ServerUser, Integer>() {
                    public Integer select(ServerUser serverUser) {
                        return (int) serverUser.getId();
                    }
                });
            }
        }

        MetaList<Integer> users = new MetaArrayList<Integer>();
        for (int i = 0; i < max; i++) {
            users.add((int) robotContext.getUsers().get(getRandom(0, userCount)).getId());
        }

        return users;
    }

    public abstract String getDescription();

    @Override
    public String toString() {
        return getDescription();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        RobotStrategy other = (RobotStrategy) o;
        return getDescription().equals(other.getDescription());
    }

    @Override
    public int hashCode() {
        int result = random != null ? random.hashCode() : 0;
        result = 31 * result + (robotContext != null ? robotContext.hashCode() : 0);
        return result;
    }
}
